/****************************************************************************
 *
 * Copyright (C) 2003-2009 Los Alamos National Security, LLC
 *                         Packet Analytics Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License Version 2 as
 * published by the Free Software Foundation.  You may not use, modify or
 * distribute this program under any other version of the GNU General
 * Public License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 ****************************************************************************/
/**
 * 
 */
package nfse;

import static org.junit.Assert.*;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import java.io.File;
import java.sql.*;
import java.util.Properties;
import java.util.ArrayList;
import nfse.JDBCDatabase;

/**
 * @author bduphoff
 * 
 */
public abstract class NetFSERecordTest {

    protected ArrayList<String> logs = new ArrayList<String>();

    protected static JDBCDatabase testDB;

    protected abstract ArrayList<NetFSERecord> getRecords();

    protected abstract int getSensorID();

    protected abstract String getFileName();

    protected abstract NetFSERecord getRecord();

    protected static String getTableName() {
        return ("recordtest").toLowerCase();
    }

    /**
     * @throws java.lang.Exception
     */
    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
        try {
            NetFSEServer.processConfigFile(new File("etc/nfse/local.cnf"));
        } catch (Exception e) {
            e.printStackTrace();
        }

        Properties props = new Properties();
        props.setProperty("user", NetFSE.METADATA_USER);
        props.setProperty("password", NetFSE.METADATA_PASSWORD);
        props.setProperty("client_encoding", "UTF8");

        try {
            testDB = new JDBCDatabase("jdbc:postgresql://" + NetFSE.METADATA_HOST + "/nfsetest", props);
        } catch (Exception e) {
            testDB = new JDBCDatabase("jdbc:postgresql://" + NetFSE.METADATA_HOST + "/metadata", props);
            Statement s = testDB.createStatement();
            s.execute("create database nfsetest");
            s.close();
            testDB.closeConnection();
            testDB = new JDBCDatabase("jdbc:postgresql://" + NetFSE.METADATA_HOST + "/nfsetest", props);

        }
    }

    /**
     * @throws java.lang.Exception
     */
    @AfterClass
    public static void tearDownAfterClass() throws Exception {
        Statement s = testDB.createStatement();
        try {
            s.execute("drop table " + getTableName());
        } catch (SQLException sqle) {
            // no op
        }
        s.close();
        if (testDB != null)
            testDB.closeConnection();
    }

    /**
     * @throws java.lang.Exception
     */
    @Before
    public abstract void setUp() throws Exception;

    /**
     * @throws java.lang.Exception
     */
    @After
    public void tearDown() throws Exception {

    }

    /**
     * Test method for
     * {@link nfse.dataset.lanl.NetFSERecord#getTempTableSQL(java.lang.String)},
     * {@link nfse.dataset.lanl.NetFSERecord#getTempIndexSQL(java.lang.String)}
     * and {@link nfse.dataset.lanl.NetFSERecord#getTempInsertSQL()} .
     * 
     * Drops the table if it existed before, creates a new one, applies indexes
     * and finally inserts records.
     */
    @Test
    public void testTempTableSQL() {
        NetFSERecord rec = getRecord();
        String sql = rec.getTempTableSQL(getTableName());
        try {
            Statement s = testDB.createStatement();

            try {
                s.execute("drop table " + getTableName());
            } catch (SQLException sqle) {
            }

            s.execute(sql);
            String[] indexSQL = rec.getTempIndexSQL(getTableName());
            for (String idxSQL : indexSQL) {
                sql = idxSQL;
                s.execute(sql);
            }

            ArrayList<NetFSERecord> records = getRecords();
            for (NetFSERecord record : records) {
                sql = "insert into " + getTableName() + " values " + record.getTempInsertSQL();
                s.execute(sql);
            }

            try {
                s.execute("drop table " + getTableName());
            } catch (SQLException sqle) {
            }
            s.close();

        } catch (SQLException sqle) {
            fail(sqle.getMessage() + " ('" + sql + "')");
        }
    }

    /**
     * Test method for
     * {@link nfse.dataset.lanl.NetFSERecord#getFlexRecordFields()}.
     */
    @Test
    public abstract void testGetFlexRecordFields();

    /**
     * Test method for {@link nfse.dataset.lanl.NetFSERecord#getIndexedFields()}.
     */
    @Test
    public abstract void testGetIndexedFields();

    /**
     * Test method for {@link nfse.dataset.lanl.NetFSERecord#isAlert()}.
     */
    @Test
    public abstract void testIsAlert();

    /**
     * Test method for {@link nfse.dataset.lanl.NetFSERecord#getAlertMessage()}.
     */
    @Test
    public void testGetAlertMessage() {
        NetFSERecord rec = getRecord();
        assertTrue(rec.getAlertMessage() == null || rec.getAlertMessage().length() == 0);
    }

    /**
     * Test method for
     * {@link nfse.dataset.lanl.NetFSERecord#generate(java.lang.String, int)}.
     */
    @Test
    public void testGenerateStringInt() {
        getRecords();
    }

    /**
     * Test method for {@link nfse.NetFSERecord#getEndTS()}.
     */
    @Test
    public void testTimestamps() {
        ArrayList<NetFSERecord> records = getRecords();
        for (NetFSERecord record : records) {
            assertEquals(record.getStartTS(), record.getEndTS());
        }
    }

    /**
     * Test method for {@link nfse.NetFSERecord#getStartTS()}.
     */
    @Test
    public void testGetStartTS() {
        NetFSERecord rec = getRecord();
        assertNotNull(rec.getStartTS());
        assertEquals(rec.getTimestamp(), rec.getStartTS());
    }

    /**
     * Test method for {@link nfse.NetFSERecord#setStartTS(java.sql.Timestamp)}.
     */
    @Test
    public void testStartTS() {
        NetFSERecord rec = getRecord();
        Timestamp temp = rec.getStartTS();
        Timestamp ts = Timestamp.valueOf("1976-04-05 00:00:00.0");
        rec.setStartTS(ts);
        assertEquals(ts, rec.getStartTS());
        rec.setStartTS(temp);
    }


    /**
     * Test method for {@link nfse.NetFSERecord#toRecord()}.
     */
    @Test
    public void testToRecord() {
        String record = getRecord().toRecord();
        assertNotNull(record);
        if (record.length() == 0)
            fail("toRecord returned a zero length String.");
    }

    /**
     * Test method for {@link nfse.NetFSERecord#isSyslog()}.
     */
    @Test
    public abstract void testIsSyslog();

    /**
     * Test method for {@link nfse.NetFSERecord#setTypeName(java.lang.String)}.
     */
    @Test
    public void testTypeName() {
        NetFSERecord rec = getRecord();
        String name = rec.getTypeName();
        assertNotNull("Name cannot be null", name);
        if (name.length() == 0)
            fail("Type name was zero length.");
        rec.setTypeName(rec.getTypeName() + "modified");
        assertEquals(name + "modified", rec.getTypeName());
    }

    /**
     * Test attribute defaults
     */
    @Test
    public abstract void testDefaults();

    /**
     * Test method for {@link nfse.NetFSERecord#setTypeID(int)}.
     */
    @Test
    public void testTypeID() {
        NetFSERecord rec = getRecord();
        int id = rec.getTypeID() + 5;
        rec.setTypeID(id);
        assertEquals(id, rec.getTypeID());
        rec.setTypeID(id - 5);
    }

    /**
     * Test method for {@link nfse.NetFSERecord#setSensorID(int)}.
     */
    @Test
    public void testSensorID() {
        NetFSERecord rec = getRecord();
        assertTrue("Sensor ID not -1", rec.getSensorID() != -1);
        assertEquals(getSensorID(), rec.getSensorID());
        int sensorID = rec.getSensorID();
        int id = sensorID + 5;
        rec.setSensorID(id);
        assertEquals(id, rec.getSensorID());
    }

    /**
     * Test method for {@link nfse.NetFSERecord#getInitialString()}.
     */
    @Test
    public void testInitialString() {
        ArrayList<NetFSERecord> records = getRecords();
        for (int i = 0; i < records.size(); i++) {
            NetFSERecord record = records.get(i);
            String log = logs.get(i);
            assertEquals(log, record.getInitialString());
        }
        NetFSERecord rec = getRecord();
        rec.setInitialString("test");
        assertEquals("test", rec.getInitialString());
    }

    /**
     * Test method for {@link nfse.NetFSERecord#getTimestamp()}.
     */
    @Test
    public void testTimestamp() {
        NetFSERecord rec = getRecord();
        long ts = 100000000;
        rec.setTimestamp(new Timestamp(ts));
        Timestamp ts2 = rec.getTimestamp();
        assertEquals(ts, ts2.getTime());
    }

    /**
     * Test method for {@link nfse.NetFSERecord#setSrcAddr(java.lang.String)}.
     */
    @Test
    public void testSrcAddr() {
        NetFSERecord rec = getRecord();
        rec.setSrcAddr("1.2.3.4");
        assertEquals("1.2.3.4", rec.getSrcAddr());
        assertEquals(16909060, rec.getSrcIP());
        rec.setSrcAddr("0.0.0.0");
        assertEquals("0.0.0.0", rec.getSrcAddr());
        assertEquals(0, rec.getSrcIP());
        rec.setSrcIP(16909060);
        assertEquals("1.2.3.4", rec.getSrcAddr());
        assertEquals(16909060, rec.getSrcIP());
    }

}
